package com.slliver.controller;


import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
@RestController
@RequestMapping("/sentinel/test")
public class TestController {

    private static final String RESOURCE_NAME = "hello";
    private static final String RESOURCE_NAME_DEGRADE = "degrade";


    /**
     * 为资源定义服务降级规则
     */
    @PostConstruct  // spring加载bean的时候调用此方法
    private static void initDegradeRule() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource(RESOURCE_NAME_DEGRADE);
        // 设置规则频率：降级的规则就是异常数
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        // 设置阈值，即达到多少触发降级
        rule.setCount(2);
        // 触发熔断最小请求数，即最小请求2次2次都异常才触发熔断降级
        rule.setMinRequestAmount(2);
        // 统计时长，默认1秒
        rule.setStatIntervalMs(60 * 1000);
        // 上面设置的意思：在1分钟内执行了2次请求并且出现了2次异常，就会触发熔断降低

        // 熔断降级时长10秒
        // 一旦触发了熔断降级，再次请求对应的接口就会直接调用降级方法
        // 10秒熔断时间过去后，进入半开状态，恢复接口的请求调用，如果第一次请求就异常，再次熔断，不会根据设置进行熔断
        rule.setTimeWindow(10);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }

    @GetMapping("/degrade")
    @SentinelResource(value = RESOURCE_NAME_DEGRADE, entryType = EntryType.IN, blockHandler = "blockHandlerForDegrade")
    public String degrade(String id) {

        throw new RuntimeException("抛出异常");


        // return "调用degrade方法成功，可以正常访问...";
    }

    // 原方法调用被熔断降级的时候调用
    public String blockHandlerForDegrade(String id, BlockException ex) {
        log.error("调用degrade方法失败 ==>> {}", ex);
        return "调用degrade方法失败，被熔断降级操作了";
    }

    // 原方法调用出现异常的处理方法
    public String fallbackForDegrade(String id, Throwable e) {
        log.error("调用degrade方法异常 ==>> {}", e);
        return "调用degrade方法失败，发生异常...";
    }
}
